package com.fwtai.bean;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * 通用的键值对数据结构
 * @作者 田应平
 * @版本 v1.0
 * @提示 表单提交的字段和数据库字段(字段大小写一致)的话，处理表单更为方便
 * @创建时间 2017年1月12日 13:13:05
 * @QQ号码 444141300
 * @官网 http://www.fwtai.com
*/
public final class PageFormData extends HashMap<String,Object>{

  public PageFormData(){}

  public PageFormData(final int initialCapacity){
    super(initialCapacity);
  }

  /**推荐使用,能获取到表单或ajax提交传参数和值或参数不传值的方法,用法 new PageFormData(request); */
  public PageFormData(final HttpServletRequest request){
    final Enumeration<String> paramNames = request.getParameterNames();
    while(paramNames.hasMoreElements()){
      final String key = paramNames.nextElement().trim();
      if(key.equals("_"))continue;
      String value = request.getParameter(key);
      if(value != null && value.length() > 0){
        value = value.trim();
        if(checkNull(value))
          continue;
        this.put(key,value);
      }
    }
  }

  /**推荐使用,能获取到表单或ajax提交传参数和值或参数不传值的方法,用法 new PageFormData(request); */
  public PageFormData(final HttpServletRequest request,final int initialCapacity){
    super(initialCapacity);
    final Enumeration<String> paramNames = request.getParameterNames();
    while(paramNames.hasMoreElements()){
      final String key = paramNames.nextElement().trim();
      if(key.equals("_"))continue;
      String value = request.getParameter(key);
      if(value != null && value.length() > 0){
        value = value.trim();
        if(checkNull(value))
          continue;
        this.put(key,value);
      }
    }
  }

  /**此方法可以预防xss攻击,精简版,一般情况使用此方式,若有问题使用xssFilter()方法。用法：new PageFormData().htmlEscape(request);*/
  public PageFormData htmlEscape(final HttpServletRequest request){
    final Enumeration<String> paramNames = request.getParameterNames();
    while(paramNames.hasMoreElements()){
      final String key = paramNames.nextElement().trim();
      if(key.equals("_")) continue;
      String value = request.getParameter(key);
      if(value != null && value.length() > 0){
        value = value.trim();
        if(checkNull(value))
          continue;
        this.put(key,htmlEscape(value));
      }
    }
    return this;
  }

  /**此方法可以预防xss攻击,不得已时才使用此方式,用法：new PageFormData().xssFilter(request,"img_front","img_reverse");*/
  public PageFormData xssFilter(final HttpServletRequest request,final String... keys){
    final Enumeration<String> paramNames = request.getParameterNames();
    while(paramNames.hasMoreElements()){
      final String key = paramNames.nextElement().trim();
      if(key.equals("_")) continue;
      String value = request.getParameter(key);
      if(value != null && value.length() > 0){
        value = value.trim();
        if(checkNull(value))
          continue;
        boolean b = false;
        if(keys.length > 0){
          for(int i = keys.length - 1; i >= 0; i--){
            if(key.equals(keys[i])){
              this.put(key,value);
              b = true;
              break;
            }
          }
          if(b){
            continue;
          }
        }
        this.put(key,filterReplace(value));
      }
    }
    return this;
  }

  private String filterReplace(final String input){
    final StringBuilder escaped = new StringBuilder(input.length() * 2);
    for(int i = 0; i < input.length(); ++i) {
      char character = input.charAt(i);
      final String reference = normalConvert(character);
      if (reference != null) {
        escaped.append(reference);
      } else {
        escaped.append(character);
      }
    }
    return escaped.toString();
  }

  /**精简版的过滤html元素标签的xss攻击*/
  private String htmlEscape(final String input){
    final StringBuilder escaped = new StringBuilder(input.length() * 2);
    for(int i = 0; i < input.length(); ++i) {
      char character = input.charAt(i);
      final String reference = convert(character);
      if (reference != null) {
        escaped.append(reference);
      } else {
        escaped.append(character);
      }
    }
    return escaped.toString();
  }

  /**精简版的替换过滤html元素标签*/
  private String convert(final char character){
    switch(character){
      case '&':
        return "&amp;";
      case '\'':
        return "&#39;";
      case '<':
        return "&lt;";
      case '>':
        return "&gt;";
      default:
        return null;
    }
  }

  private String normalConvert(final char character){
    switch(character){
      case '"':
        return "&quot;";
      case '&':
        return "&amp;";
      case '\'':
        return "&#39;";
      case '<':
        return "&lt;";
      case '>':
        return "&gt;";
      default:
        return null;
    }
  }

  /**构建获取POST方式的form表体json数据转PageFormData,用法:new PageFormData().build(request);*/
  public PageFormData build(final HttpServletRequest request){
    try {
      final StringBuilder sb = getFormBody(request);
      if(sb.length() > 0){
        getValue(JSON.parseObject(sb.toString(),HashMap.class),this);
      }
    } catch (final Exception ignored){}
    return this;
  }

  /**构建获取POST方式的form表体json数据,用法:new PageFormData().buildJSONObject(request);*/
  public JSONObject buildJSONObject(final HttpServletRequest request){
    final JSONObject result = new JSONObject();
    try {
      final StringBuilder sb = getFormBody(request);
      if(sb.length() > 0){
        final JSONObject original = JSON.parseObject(sb.toString(),JSONObject.class);
        getValue(original,result);
      }
    } catch (final Exception ignored){}
    return result;
  }

  /**构建获取POST方式的form表体json数据数据,用法:new PageFormData().buildJSONArray(request);*/
  public JSONArray buildJSONArray(final HttpServletRequest request){
    final JSONArray jsonArray = new JSONArray();
    try {
      final StringBuilder sb = getFormBody(request);
      if(sb.length() > 0){
        final JSONArray array = JSON.parseArray(sb.toString().trim());
        for(int i = 0; i < array.size(); i++){
          final JSONObject object = array.getJSONObject(i);
          final JSONObject objectObject = new JSONObject();
          getValue(object,objectObject);
          if(!objectObject.isEmpty())jsonArray.add(objectObject);
        }
      }
    } catch (final Exception ignored){}
    return jsonArray;
  }

  public static StringBuilder getFormBody(final HttpServletRequest request) throws IOException{
    final StringBuilder sb = new StringBuilder();
    final BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(),StandardCharsets.UTF_8));
    String s = "";
    while((s = br.readLine()) != null){
      sb.append(s);
    }
    br.close();
    return sb;
  }

  public static StringBuilder getFormJson(final HttpServletRequest request) throws IOException{
    final BufferedReader br = request.getReader();
    String str = "";
    final StringBuilder sb = new StringBuilder();
    while((str = br.readLine()) != null){
      sb.append(str);
    }
    return sb;
  }

  private boolean checkNull(final String value){
    if(value == null) return true;
    if(value.length() == 0)return true;
    if(value.equals("_"))return true;
    if(value.equalsIgnoreCase("undefined"))return true;
    return value.equalsIgnoreCase("null");
  }

  public void getValue(final Map<String, Object> original,final Map<String, Object> result){
    if(!original.isEmpty()){
      for (final Map.Entry<String,Object> entry : original.entrySet()){
        final String key = entry.getKey();
        if(key.equals("_"))continue;
        final Object obj = entry.getValue();
        if(obj != null){
          if(obj instanceof String){
            final String value = ((String)obj).trim();
            if(checkNull(value))
              continue;
            result.put(key,value);
          }else {
            result.put(key,obj);
          }
        }
      }
    }
  }

  /** PageFormData.build(request); */
  public static Map<String, String> build(final ServletRequest request){
    final Map<String ,String > dataMap = new HashMap<>();
    // 判断是否已经将 inputStream 流中的 body 数据读出放入 attribute
    if (request.getAttribute("body") != null) {
      // 已经读出则返回attribute中的body
      return (Map<String,String>)request.getAttribute("body");
    } else {
      try {
        dataMap.putAll(JSON.parseObject(request.getInputStream(),Map.class));
        request.setAttribute("body",dataMap);
      }catch (final IOException e) {
        e.printStackTrace();
      }
      return dataMap;
    }
  }

  /**
   * 获取请求体的字符串,拿到该字符串后可调用该字符串判断是否是json对象|json数组|纯字符串再做业务处理
   * @param
   * @作者 田应平
   * @QQ 444141300
   * @创建时间 2020年5月23日 20:27:44
   */
  public static String getRequest(final HttpServletRequest request){
    try {
      final StringBuilder sb = getFormBody(request);
      return sb.length() > 0 ? sb.toString() : null;
    } catch (final Exception ignored) {}
    return null;
  }

  public String getString(final String key){
    final Object value = get(key);
    if(value == null)return null;
    final String strVal = (String) value;
    if(checkNull(strVal))return null;
    return strVal.trim();
  }

  /**获取值并移除key对应的value*/
  public String getStringRemove(final String key){
    final Object value = get(key);
    if(value == null)return null;
    final String strVal = (String) value;
    if(checkNull(strVal))return null;
    remove(key);
    return strVal.trim();
  }

  /**获取日期时间格式：yyyy-MM-dd HH:mm:ss,对应数据库表类型的 datetime*/
  public LocalDateTime getDateTimeSecond(final String key){
    final Object value = get(key);
    if(value == null)return null;
    final String strVal = (String) value;
    if(checkNull(strVal))return null;
    final String pattern = "\\d{4}(\\-|\\/|.)\\d{1,2}\\1\\d{1,2}\\s\\d{1,2}:\\d{1,2}:\\d{1,2}";
    final boolean matches = Pattern.matches(pattern,strVal);
    if(!matches) return null;
    return LocalDateTime.parse(strVal,DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
  }

  /**获取日期时间格式：yyyy-MM-dd,对应数据库表类型的 date*/
  public LocalDate getDate(final String key){
    final Object value = get(key);
    if(value == null)return null;
    final String strVal = (String) value;
    if(checkNull(strVal))return null;
    final String pattern = "\\d{4}(\\-|\\/|.)\\d{1,2}\\1\\d{1,2}";
    final boolean matches = Pattern.matches(pattern,strVal);
    if(!matches) return null;
    try {
      return LocalDate.parse(strVal,DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    } catch (final Exception ignored) {
      return null;
    }
  }

  /**日期格式化-已不推荐，日期时间格式均为int类型*/
  public LocalDateTime getYyyyMMddHHmmss(final String value){
    return LocalDateTime.parse(value,DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
  }

  /**日期格式化-已不推荐，日期时间格式均为int类型*/
  public LocalDateTime getYyyyMMddHHmm(final String value){
    return LocalDateTime.parse(value,DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
  }

  /**日期格式化-已不推荐，日期时间格式均为int类型*/
  public LocalDate getYyyyMMdd(final String value){
    return LocalDate.parse(value,DateTimeFormatter.ofPattern("yyyy-MM-dd"));
  }

  public Integer getInteger(final String key){
    try {
      final Object value = get(key);
      if(value == null)return null;
      if(value instanceof Integer)return (Integer) value;
      if(value instanceof String){
        final String strVal = (String) value;
        if(checkNull(strVal))return null;
      }
      return Integer.parseInt(String.valueOf(value));
    } catch (final Exception ignored) {
      return null;
    }
  }

  public Long getLong(final String key){
    try {
      final Object value = get(key);
      if(value == null)return null;
      if(value instanceof Long)return (Long) value;
      if(value instanceof String){
        final String strVal = (String) value;
        if(checkNull(strVal))return null;
      }
      return Long.parseLong(String.valueOf(value));
    } catch (final Exception ignored) {
      return null;
    }
  }

  public boolean getBoolean(final String key){
    final Object value = get(key);
    if(value == null) return false;
    try {
      return Boolean.parseBoolean((String) value);
    } catch (final Exception ignored) {
      return false;
    }
  }

  public Double getDouble(final String key){
    try {
      final Object value = get(key);
      if(value == null)return null;
      if(value instanceof Double)return (Double) value;
      if(value instanceof String){
        final String strVal = (String) value;
        if(checkNull(strVal))return null;
      }
      return Double.parseDouble(String.valueOf(value));
    } catch (final Exception ignored) {
      return null;
    }
  }

  /**注意是否需要处理保留的几位小数点*/
  public BigDecimal getBigDecimal(final String key){
    try {
      final Object value = get(key);
      if(value == null)return null;
      if(value instanceof BigDecimal)return (BigDecimal) value;
      final String strVal = value.toString();
      if(strVal.length() == 0)return null;
      final String pattern = "[0-9]\\d*\\.?\\d*";
      final boolean matches = Pattern.matches(pattern,strVal);
      if(!matches) return null;
      return new BigDecimal(strVal);
    } catch (final Exception ignored) {
      return null;
    }
  }
}